﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if !NETFX_CORE
using System.Runtime.InteropServices.WindowsRuntime;
using System.Windows.Media.Imaging;
using System.Drawing;
#else
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Storage.FileProperties;
#endif
using Cofe.Core.Utils;


namespace Cofe.Core
{
    //[Windows.UI.Xaml.Markup.ContentProperty(Name = "BitmapSource")] //Doesnt work
    public class BitmapContainer : IDisposable
    {
        #region Constructor

        public BitmapContainer()
        {
            PixelWidth = 0;
            PixelHeight = 0;
            _bmpFunc = (e) => null;
            _streamFunc = (e, mt) => new StreamContainer();
        }

        public static BitmapContainer FromWritableBitmap(WriteableBitmap writableBitmap, string path = null, object prop = null)
        {
            return new BitmapContainer()
            {
                _property = prop,
                _entity = writableBitmap,
                PixelWidth = writableBitmap.PixelWidth,
                PixelHeight = writableBitmap.PixelHeight,
                _bmpFunc = (e) => (WriteableBitmap)e,
                _streamFunc = (e, mt) =>
                    {
                        lock (e)
                        {
                            if (path != null)
                            {
#if !NETFX_CORE
                                return StreamContainer.FromIOStream(((WriteableBitmap)e).ToStream(mt), path);
#else
                            return StreamContainer.FromRandomAccessStream(((WriteableBitmap)e).ToStream(mt), path);
#endif
                            }
                            else return StreamContainer.FromIOStream(ConverterUtils.ToStream((WriteableBitmap)e, mt), path);
                        }
                    }
            };
        }

#if !NETFX_CORE
        public static BitmapContainer FromBitmapSource(BitmapSource bitmapSource, string path = null, object prop = null)
        {

            return FromWritableBitmap(new WriteableBitmap(bitmapSource), path, prop);
        }

        public static BitmapContainer FromStream(StreamContainer stream, string path = null, object prop = null)
        {
            return BitmapContainer.FromBitmap(new System.Drawing.Bitmap(stream.Stream), path, prop);
        }        

        public static BitmapContainer FromBitmap(Bitmap bitmap, string path = null, object prop = null)
        {
            if (bitmap == null)
                throw new ArgumentNullException();

            return new BitmapContainer()
            {
                _property = prop,
                _entity = bitmap,
                PixelHeight = bitmap.Height,
                PixelWidth = bitmap.Width,
                _bmpFunc = (b) => 
                    {
                        //Console.WriteLine("bmpFunc");
                        //Console.WriteLine(b);
                        var bitmapSource = BitmapSourceUtils.CreateBitmapSourceFromBitmap((Bitmap)b);
                        return bitmapSource == null ? null : new WriteableBitmap(bitmapSource);
                    },
                _streamFunc = (b, mt) =>
                    {
                        lock (b)
                        {
                            var ms = new MemoryStream();
                            System.Drawing.Imaging.ImageFormat fmt;
                            switch (mt)
                            {
                                case MediaType.Bmp: fmt = System.Drawing.Imaging.ImageFormat.Bmp; break;
                                case MediaType.Jpeg: fmt = System.Drawing.Imaging.ImageFormat.Jpeg; break;
                                case MediaType.Png: fmt = System.Drawing.Imaging.ImageFormat.Png; break;
                                default: throw new NotSupportedException();
                            }
                            ((Bitmap)b).Save(ms, fmt);
                            ms.Seek(0, SeekOrigin.Begin);
                            return StreamContainer.FromIOStream(ms, path);
                        }
                    }

            };
        }

#endif

#if !NETFX_CORE

#else
        public static BitmapContainer FromStorageItemThumbnail(StorageItemThumbnail bitmapSource, string path = null, object prop = null)
        {
            var wb = new WriteableBitmap((int)bitmapSource.OriginalWidth, (int)bitmapSource.OriginalHeight);
            wb.SetSource(bitmapSource);
            return FromWritableBitmap(wb, path, prop);
        }
#endif


        #endregion

        #region Methods

        public void Dispose()
        {
            if (DisposeEntity)
                if (_entity != null)
                {
                    if (_entity is IDisposable)
                        (_entity as IDisposable).Dispose();
                }

            _entity = null;
            _bmp = null;
            _streamFunc = null;
            _bmpFunc = null;
        }

        public StreamContainer GetStream(MediaType mt = MediaType.Unknown)
        {
            if (mt == MediaType.Unknown)
            {
                var webResourceAttrib =
                    _property == null ? null :
                    AttributeUtils<WebResourceAttribute>.FindAttribute(_property);
                if (webResourceAttrib == null)
                    throw new ArgumentException("MediaType not defined.");
                else mt = webResourceAttrib.MediaType;
            }

            if (_streamFunc == null)
                throw new Exception("Already disposed.");
            return _streamFunc(_entity, mt);
        }

        #endregion

        #region Data

        object _property = null;
        object _entity = null;
        WriteableBitmap _bmp = null;
        Func<object, MediaType, StreamContainer> _streamFunc = (e, mt) => null;
        Func<object, WriteableBitmap> _bmpFunc = (e) => null;
        bool _disposeEntity = true;

        #endregion

        #region Public Properties

        public WriteableBitmap BitmapSource { get { return _bmp ?? (_bmp = _bmpFunc(_entity)); } }
        public int PixelWidth { get; private set; }
        public int PixelHeight { get; private set; }


        public object Entity { get { return _entity; } }
        /// <summary>
        /// When Dispose is called, specify if dispose the holding entity (e.g. Bitmap/WritableBitmap).
        /// </summary>
        public bool DisposeEntity { get { return _disposeEntity; } set { _disposeEntity = value; } }

        #endregion



    }
}
